package com.springboot.middle.give_the_thumbsup.server.service;

import com.google.common.base.Strings;
import com.springboot.middle.give_the_thumbsup.model.mapper.PraiseMapper;
import com.springboot.middle.give_the_thumbsup.server.dto.PraiseRankDto;
import org.redisson.api.RList;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
public class RedisPraiseImpl implements RedisPraise{
    private static final Logger log = LoggerFactory.getLogger(RedisPraiseImpl.class);
    //定义点赞博客时刻缓存存储时的Key
    private static final String keyBlog = "RedisBlogPraiseMap";

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private PraiseMapper praiseMapper;

    /**
     * 缓存当前用户点赞博客的记录-包括正常点赞, 取消点赞
     *
     * @param blogId 博客id
     * @param userId 用户id
     * @param status 状态(1=正常, 0=取消点赞)
     * @throws Exception exception
     */
    @Override
    public void cachePraiseBlog(Integer blogId, Integer userId, Integer status) throws Exception {
        //创建用于获取分布式锁的key
        final String lockName = new StringBuffer("blogRedissonPraiseLock").append(blogId).append(userId).append(status).toString();
        //获取分布式锁实例
        RLock lock = redissonClient.getLock(lockName);
        boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
        try {
            if (res) {
                //判断参数合法性
                if (blogId != null && userId != null && status != null) {
                    final String key = blogId + ":" + userId;
                    RMap<String, Integer> praiseMap = redissonClient.getMap(keyBlog);
                    //如果status=1, 当前用户执行点赞操作
                    //如果status=0, 当前用户执行取消点赞操作
                    if (status == 1) {
                        //点赞操作, 需要将对应的信息(这里是用户的id)添加进RMap中
                        praiseMap.putIfAbsent(key, userId);
                    } else if (status == 0){
                        //取消点赞操作, 需要将对应的信息(这里是唯一那个key)从RMap中移除
                        praiseMap.remove(key);
                    }
                }
            }
        } catch (Exception e) {
            log.error("RedisPraiseImpl发生错误");
            throw e;
        } finally {
            if (lock.isLocked()) {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }
    }

    /**
     * 获取当前博客总的点赞数
     *
     * @param blogId 博客id
     * @return 当前博客总的点赞数
     * @throws Exception exception
     */
    @Override
    public Long getCacheTotalBlog(Integer blogId) throws Exception {
        //定义最终的返回值, 初始时为0
        Long result = 0L;
        //判断参数的合法性
        if (blogId != null) {
            //定义Redisson的RMap映射数据结构实例
            RMap<String, Integer> praiseMap = redissonClient.getMap(keyBlog);
            //获取RMap中所有的键值对
            Map<String, Integer> dataMap = praiseMap.readAllMap();
            //判断取出来的键值对列表是否有值
            if (dataMap != null && dataMap.keySet() != null) {
                Set<String> set = dataMap.keySet();
                Integer bId;
                //循环遍历所有的键列表, 查看是否有当以前博客id开头的数据记录
                for (String key : set) {
                    //由于每个键的取值是由"博客id:用户id"这样的格式构成
                    //因而可以通过分隔符, 得到: 博客id与用户id参数的值
                    if (!Strings.isNullOrEmpty(key)) {
                        String[] split = key.split(":");
                        if (split != null && split.length > 0) {
                            bId = Integer.valueOf(split[0]);
                            if (blogId.equals(bId)) {
                                result += 1;
                            }
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * 触发博客点赞总数排行榜
     *
     * @throws Exception exception
     */
    @Override
    public void rankBlogPraise() throws Exception {
        //定义用于缓存排行榜的key
        final String key = "praiseRankListKey";
        //根据数据库查询语句得到已经排好续的博客实体对象列表
        List<PraiseRankDto> praiseRankList = praiseMapper.getPraiseRank();
        //判断列表中是否有数据
        if (praiseRankList != null && praiseRankList.size() > 0) {
            RList<PraiseRankDto> rList = redissonClient.getList(key);
            //先清空缓存里的列表
            rList.clear();
            //将得到的最新的排行榜更新至缓存中
            rList.addAll(praiseRankList);
        }
    }

    /**
     * 获得博客点赞排行榜
     *
     * @return 博客点赞排行榜
     * @throws Exception exception
     */
    @Override
    public List<PraiseRankDto> getBlogPraiseRank() throws Exception {
        //定义缓存排行榜的Key
        final String key = "praiseRankListKey";
        RList<PraiseRankDto> rList = redissonClient.getList(key);
        return rList;
    }
}
